אז אני מתאר שזה יהיה מאוד מסורבל ולא כדאי לעשות מחלקה אחת ממש גדולה
שתכיל בתוכה את כל המתודות לחיבור למסד נתונים, בדיקת התחברות משתמשים,
התנתקות, הוספת תגובה חדשה וכו', אלא לעשות את זה בקלאסים נפרדים.
אבל הבעיה היא שאם אני יוצר יותר מקלאס אחד לחיבור עם מסד נתונים אז זה לא נראה
לי ממש יעיל שיהיו לי 2 חיבורים לאותו מסד כשאני יכול להשתמש באחד..
לדוגמה:
{
function __construct($host , $user , $pass , $db)
{
parent::__construct($host,$user,$pass,$db);
}
function login()
{
// log in code..
}
function logout()
{
// log out code..
}
}
class forum extends mysqli
{
function __construct($host , $user , $pass , $db)
{
parent::__construct($host,$user,$pass,$db);
}
function addComment()
{
// add comment code..
}
}
פה אני צריך להשתמש ב-2 חיבורים שונים לאותו מסד נתונים בשביל המחלקות השונות.
מה האפשרות הכי טובה במצב כזה? ;-)
26 תשובות
למה שתוריש מ-mysqli? איך האובייקטים הללו קשורים ל-mysqli מלבד העובדה שיש לך צורך להשתמש בפעולות של mysqli? יש הבדל בין הורשה לבין include/require.
וגם כשתצמצם הכול לחיבור אחד, לא הייתי ממליץ לך לעשות סינגלטון כי זה לא באמת מועיל מאוד.
אה הבנתי למה אתה מתכוון, באמת אין צורך.
ורק כדי שאני אהיה בטוח, זה הדבר הנכון לעשות?:
{
static $con;
function __construct($host , $user , $pass , $db)
{
self::$con = new mysqli($host,$user,$pass,$db);
}
function login()
{
$query = self::$con->query("SELECT...");
}
function logout()
{
// log out code..
}
}
$db = new user('localhost' , 'root' , '' , 'database');
$db->login(); // סתם לדוגמה
ובקשר לשאלה שלי, עדיין לא לגמרי הבנתי מה כדאי לעשות. אשמח אם תסביר שוב. (-:
לא.
למה user צריכה לקבל פרטי חיבור למסד?
private $id;
public $username, $age;
public function __construct($id) {
$this->id = $id;
}
public function doSomething() {
$mysqli = new mysqli(....);
$q = $mysqli->query("query...");
}
}
אצלי פרטי הכניסה שמורים כמאפיינים במחלקה עצמה של mysqli, ככה שאני לא צריך להזין אותם בכל חיבור.
*שים לב שבכל מתודה שמתקשרת עם המסד, תצטרך להתחבר מחדש. אני משתמש ב-singleton כדי למנוע המון חיבורים.
"*שים לב שבכל מתודה שמתקשרת עם המסד, תצטרך להתחבר מחדש. אני משתמש ב-singleton כדי למנוע המון חיבורים."
למה? לא הבנתי מה הבעיה ליצור תכונה של החיבור למסד במחלקה (כמו שעשיתי - con$), ואז בכל מתודה להשתמש בחיבור הקיים?
ובקשר לסינגלטון - אני אבדוק את זה לעומק. תודה על התגובה. (:
ד"א, אם אני יוצר מופע mysqli אחד, ואז מעביר אותו (או מצביע אליו) לכל קלאס כפרמטר (אפשר גם להגיע אליו כמשתנה גלובלי) ואז להשתמש בו, זה יהיה יעיל?
אין בעיה ליצור תכונה סטטית של החיבור למסד. אבל זה לא אמור להיות שם.
מחלקה של משתמש אמורה להכיל רק מה שקשור למשתמש. החיבור לא קשור אליו.
ואם אתה כבר יוצר מופע mysqli אחד, פשוט תשתמש ב-singleton. ככה אתה לא תצטרך לשלוח אותו כל פעם כפרמטר.
בכל מקום תוכל לקבל את החיבור ולעשות איתו מה שתרצה.
סינגלטון מגביל אותך בכמה חיבורים, וזה לא דבר חכם, כי לפעמים יש צורך להתחבר למסדים שונים. תצור מופע אחד ותשתמש בו.
האמת שראיתי באינטרנט הרבה שלא ממליצים על סינגלטון..
אבל מהסיבה הזאת כרגע זה לא בעיה עבורי, כי יש לי רק מסד אחד.
- תצור מופע אחד ותשתמש בו.
איך להשתמש בו? לעשות הכל בקלאס אחד יהיה ממש מסורבל וארוך..\:
@cthulhu
נכון. אבל אם יש מסד אחד (כמו כאן) אז זה מצוין.
חוץ מזה שאתה תמיד יכול להרחיב את זה ליותר ממסד אחד בכך שתעביר כפרמטר לפונקציה הסטטית (זאת שמחזירה את המופע) את המסד שאליו אתה רוצה את החיבור, והיא תחזיר לך את המופע המתאים. משהו כזה:
private static $connection= array();
public static function connection($db) {
if (!array_key_exists($db, self::$connection)) {
self::$connection[$db] = new self('localhost','un','pw',$db):
}
return self::$connection[$db];
}
}
$db1 = database::connection('database1');
$db2 = database::connection('database2');
בינתיים יש לו מסד אחד. כשהוא ירצה להוסיף מסד, הוא יצטרך לשנות חיבורים במקומות רבים. להשתמש בסינגלטון בעבודה עם מסדים - לא נכון.
אם הוא ישתמש במה שהראיתי למעלה הוא יוכל להוסיף כמה מסדים שירצה בלי שום בעיה.
זה לא רק עניין של מס' חיבורים למסדים שונים. זה גם עניין של מבנה קוד רע. זה שווה ערך ל-global במבנה. בגלל המבנה שלו אי אפשר לאפשר סאבקלאסים. וכן, object pool זה דבר נחמד, אך עדיין אין כאן צורך בזה.
אני לא רואה בזה שום בעיה.
המתודה הסטטית פשוט מחזירה לך את החיבור למסד ואתה יכול לגשת אליה ולקבל את החיבור מכל מקום.
ואם בסאבקלאס אתה מתכוון לירושה, אני לא רואה סיבה לרשת מהמעטפת של mysqli.
ובנוגע להדמות שלו ל-global, אולי זה טיפה מזכיר, אבל אל תשכח שב-global אתה לא יודע בוודאות שהמשתנה החיצוני קיים ואתה הופך תלותי בו. כאן זה לא המקרה, אתה מקבל את החיבור, ואם אין חיבור כזה, אז הוא נוצר ואז אתה מקבל אותו.
מה הקשר למה שאמרתי? ולגבי "תלותי" - סינגלטון מסתיר תלויות, ככה שעדיף כאן לעשות di.
סינגלטון הוא לא תלותי, הוא לא מסתיר גם כלום. אתה לא תלוי בחיבור, אתה תמיד תקבל אותו.
למעט במקרה בו יש שגיאה, ובמקרה כזה אין הבדל בין singleton לבין כל דרך אחרת.
הבנתי איך סינגלטון פועל, ואין לי בעיה לממש אותו על אותו הקלאס ש"בונה" אותו,
אבל עדיין לא הבנתי לגמרי איך אני ממש אותו על קלאסים אחרים. (זאת המטרה שפתחתי את הנושא הזה)
אז אני אשמח שתביאו לי קוד לדוגמה של מימוש סינגלטון על יותר מקלאס אחד.
וד"א cthulhu,
הבנתי שאתה לא ממליץ על סינגלטון, אבל על מה אתה כן ממליץ עדיין לא ענית לי..
אם אתה עושה סינגלטון על המעטפת של mysqli אתה מממש אותו פעם אחת. אתה לא צריך להפוך את כל המחלקות שמשתמשות בו לסינגלטון.
אם לדעתך סינגלטון לא מסתיר תלות אז אתה ככל הנראה לא מבין עד הסוף מהו סינגלטון. כל התהליך של יצירת אובייקט מתנהל במתודה סטטית, כך שהשליטה עליו בלתי אפשרית. וכשתרצה לעשות קצת unit testing תופתע לגלות שזה לא יהיה נחמד כ"כ עם סינגלטון ותצטרך להשתמש ב-di כמו שאמרתי קודם לכן.
תראה, אני אחזור על הסיבה שפתחתי את הנושא הזה -
אני רוצה לאפשר כמה קלאסים עם אותו חיבור למסד נתונים.
אז כמו שאמרתי, אני אשמח לקוד קצר שרק יגרום לי להבין את הרעיון לאיך לעשות את זה.
תעביר לכל קלאס את המופע היחיד שיש לך בקוד. או שתעשה את זה בקונסטרוקטור או במתודה נפרדת. זה עבודה של 2 שניות. ואתה בכל מקרה תצטרך ליצור את המופע של האובייקטים הללו איכן שהוא בקוד.
@cthulhu
יכול להיות שאני לא מבין עד הסוף מהו סינגלטון. אשמח אם תסביר מה הבעיות איתו.
אני לא רואה בעיה ביצירת והחזרה של אובייקט במתודה סטטית.
cthulhu,
אתה מתכוון להעביר את המופע באמצעות פרמטר למחלקות?
class user
{
private static $msi;
function __construct($con)
{
self::$msi = $con;
}
function show()
{
$msi = self::$msi;
$query = $msi->query("SELECT ...");
}
}
$con = new mysqli('localhost' , 'root' , '' , 'db');
$msi = new user($con);
$msi->show();
ככה לדוגמה?
וד"א, אני יודע שבשפת C במקרה כמו זה להעביר מצביע כפרמטר יהיה הרבה יותר יעיל וחסכוני ,
מכיוון שמצביע שוקל רק 4 בתים, ביחס למשאב כמו זה שיכול לתפוס יותר מקום בזיכרון.
אז השאלה שלי היא האם גם ב-php זה יהיה אותו דבר? כלומר, שעדיף יהיה לי לעשות את המתודה הקונסטרקטית ככה:
{
self::$msi = $con;
}
?
כן, דרך הקונסטרוקטור. רק בשביל מה לעשות את זה סטטי?
private $currentConnection;
public function __construct($dbConnection) {
$this->currentConnection = $dbConnection;
}
...
}
אלא אם כן אתה באמת צריך ליצור מיליון מופעים.
לגבי העברה "by reference" - אין כל צורך להעביר ככה חיבור, כי חיבור ב-php כבר בעצמו אוטומטית מועבר כקישור (reference) ולא כערך. במקרים מסוימים זה אפילו יהיה איטי יותר.
חשבתי שכדאי לעשות את זה סטטי כדי שלא ייוצרו חיבורים שונים למחלקה, אלא אותו חיבור כל הזמן.
ותודה רבה לגבי ההסבר! סוף סוף אני יכול ליישם את מה שרציתי. :)
לי זה עדיין מוזר להעביר כפרמטר למחלקה משהו שלא קשור למחלקה.
נראה לי מוזר.